﻿using AIVision.Inspect;
using AIVision.Model;
using AIVision.Model.EntityModels;
using AIVision.Model.InspectModels;
using HalconDotNet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace XRVision.DLCheckUnit
{
    public class DLObjCheckUnitInstance : ICheckUnit
    {
        private DLInspect dLInspect;
        private string _resource_path;
        public string ResourcePath
        {
            get
            {
                return _resource_path;
            }
            set
            {
                lock (_procedure_path_lock)
                {
                    _procedure_path_initialized = false;
                }
                _resource_path = value;
            }
        }

        public List<DefectItemDto> defectItems;


        private EnumInspectType inspectType = EnumInspectType.OBJ;
        public EnumInspectType InspectType { get => inspectType; }

        private int okScore;
        private Lazy<HDevProgram> _Program;
        private Lazy<HDevProcedure> _GetInspectImage;
        private Lazy<HDevProcedure> _GetInspectArea;
        public void Init(string hcFilePath, List<DefectItemDto> defectItems, int okScore)
        {
            throw new Exception("初始化失败，检查类型匹配错误！");
        }

        public void Init(string hcFilePath, string processFilePath, string modelFilePath, HTuple dlDevice, List<DefectItemDto> defectItems,int okScore)
        {
            this.defectItems = defectItems;
            _resource_path = hcFilePath;
            this.okScore = okScore;
            _Program = new Lazy<HDevProgram>(() => new HDevProgram(_resource_path));
            _GetInspectImage = new Lazy<HDevProcedure>(() => new HDevProcedure(_Program.Value, "GetInspectImage"));
            _GetInspectArea = new Lazy<HDevProcedure>(() => new HDevProcedure(_Program.Value, "GetInspectArea"));
            dLInspect = new DLInspect(processFilePath, modelFilePath, dlDevice);
            dLInspect.Init();
        }

        public void Stop()
        {
            dLInspect.Stop();
            dLInspect = null;
        }
        public InspectResultModel ExUnitCheck(HObject image)
        {
            InspectResultModel result = new InspectResultModel();
            result.Defects = new Dictionary<string, HObject>();
            result.SourceImage = image;
            result.InspectImage = null;
            result.InspectType = EnumInspectType.OBJ.ToString();
            result.Score = 0;
            result.OKScore = okScore;
            try
            {
                dLInspect.ExInspect(image);
                result.InspectImage = dLInspect.InferenceImage;
            }
            catch (Exception ex)
            {
                result.InspectImage = image;
                result.Defects.Add("DL推理错误！", null);
               
                return result;
            }


            for (int j = 0; j < dLInspect.ObjNames.Length; j++)
            {
                var checkItem = defectItems.FirstOrDefault(m => m.DefectCode == dLInspect.ObjNames.SArr[j]);
                if (checkItem == null)   //如果未配置该缺陷项目，该缺陷忽略
                    continue;
                HObject tmpRegion;
                HOperatorSet.SelectObj(dLInspect.ObjRange, out tmpRegion, j+1);
                result.Defects.Add(checkItem.DefectName + (j+1).ToString(), tmpRegion);
            }

            if (dLInspect.ObjNames.Length == 5)
                result.Score = okScore;
            else
                result.Score = 0;

            return result;
        }

        public void GetDLSpectImage(HObject SourceImage, out HObject InspectImage)
        {
            //AddResourcePathToProcedurePath();
            using (HDevProcedureCall call = _GetInspectImage.Value.CreateCall())
            {
                SetParameter(call, "SourceImage", SourceImage);
                call.Execute();
                InspectImage = GetParameterHObject(call, "InspectImage");
            }
        }
        public void GetInspectArea(HObject InspectImage, out HObject InspectArea)
        {
            //AddResourcePathToProcedurePath();
            using (HDevProcedureCall call = _GetInspectArea.Value.CreateCall())
            {
                SetParameter(call, "InspectImage", InspectImage);
                call.Execute();
                InspectArea = GetParameterHObject(call, "InspectArea");
            }
        }


        private bool _procedure_path_initialized = false;
        private object _procedure_path_lock = new object();

        #region 获取、设置参数方法
        private HTuple GetParameterHTuple(HDevProcedureCall call, string name)
        {
            return call.GetOutputCtrlParamTuple(name);
        }

        private HObject GetParameterHObject(HDevProcedureCall call, string name)
        {
            return call.GetOutputIconicParamObject(name);
        }

        private HTupleVector GetParameterHTupleVector(HDevProcedureCall call, string name)
        {
            return call.GetOutputCtrlParamVector(name);
        }

        private HObjectVector GetParameterHObjectVector(HDevProcedureCall call, string name)
        {
            return call.GetOutputIconicParamVector(name);
        }

        private void SetParameter(HDevProcedureCall call, string name, HTuple tuple)
        {
            call.SetInputCtrlParamTuple(name, tuple);
        }

        private void SetParameter(HDevProcedureCall call, string name, HObject obj)
        {
            call.SetInputIconicParamObject(name, obj);
        }

        private void SetParameter(HDevProcedureCall call, string name, HTupleVector vector)
        {
            call.SetInputCtrlParamVector(name, vector);
        }

        private void SetParameter(HDevProcedureCall call, string name, HObjectVector vector)
        {
            call.SetInputIconicParamVector(name, vector);
        }
        #endregion

        private void AddResourcePathToProcedurePath()
        {
            lock (_procedure_path_lock)
            {
                if (!_procedure_path_initialized)
                {
                    new HDevEngine().AddProcedurePath(ResourcePath);
                    _procedure_path_initialized = true;
                }
            }
        }
    }
}
